﻿using System;
using System.ComponentModel;
using System.Net;
using System.Text;
using System.Threading;
using System.Xml;
using DVDFilmoteka.Forms;
using DVDFilmoteka.Settings;
using System.Windows.Forms;

namespace DVDFilmoteka.UpdateManagement
{
    public enum ApplicationUpdateEventType { NEWVERSIONAVAILABLE, NEWBETAVERSIONAVAILABLE, NEWVERSIONNOTAVAILABLE, NEWVERSIONDOWNLOADED }

    public class ApplicationUpdateEventArgs : EventArgs
    {
        public ApplicationUpdateEventType eventType { get; set; }

        public Version ActualVersion { get; set; }
        public Object userState { get; set; }
    }

    class ApplicationUpdater
    {
        private static readonly ApplicationUpdater instance = new ApplicationUpdater();

        private const String fileSite = "http://dvdfilmoteka.googlecode.com/files/";
        private const String updateSite = "http://code.google.com/p/dvdfilmoteka/";
        private readonly WebClient webClient;
        private Thread downloadThread = null;
        
        public EventHandler<ApplicationUpdateEventArgs> OnVersionGet;

        private String tempFile;
        private DownloadProgress progressForm = null;

        /// <summary>
        /// Factory method
        /// </summary>
        /// <returns></returns>
        public static ApplicationUpdater Instance
        {
            get
            {
                return instance;
            }
        }

        /// <summary>
        /// konstruktor
        /// </summary>
        private ApplicationUpdater()
        {
            webClient = new WebClient();
            webClient.Encoding = Encoding.UTF8;            
            webClient.DownloadFileCompleted += downloadFileCompleted;

            SettingsManager manager = SettingsManager.Instance;
            if (manager.Data.UseProxy)
            {
                if (manager.Data.UseDefaultProxy)
                {
                    webClient.Proxy = WebRequest.GetSystemWebProxy();
                } else
                {
                    IWebProxy proxy = new WebProxy(manager.Data.ProxyIPAddress.ToString(), manager.Data.ProxyPort);
                    webClient.Proxy = proxy;
                }
            }
        }

        /// <summary>
        /// Zjisti aktualni verzi (asynchronne)
        /// </summary>
        public void checkNewVersionAsync(object state)
        {
            try
            {
                if (downloadThread != null && downloadThread.ThreadState == ThreadState.Running)
                {
                    MessageBox.Show(Properties.Messages.messages_gettingnewversion, Tools.AssemblyName, MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }

                downloadThread = new Thread(() => downloadDataThread(state));
                downloadThread.Start();
            }
            catch { }
        }

        /// <summary>
        /// Stahne webovou stranku v jinem threadu
        /// </summary>
        /// <param name="state"></param>
        private void downloadDataThread(object state)
        {
            try
            {
                byte[] data = webClient.DownloadData(new Uri(updateSite));
                if (data == null) return;

                string textData = webClient.Encoding.GetString(data);

                int pos = textData.IndexOf("Aktuální verze je ");
                String versionText = textData.Substring(pos + 18);
                versionText = versionText.Substring(0, versionText.IndexOf("<"));
                        
                Version actualVersion = new Version(versionText);
                String version = Tools.AssemblyVersion;
                if (version.Contains("beta")) version = version.Substring(0, version.IndexOf("beta"));
                Version myVersion = new Version(version);

                if (actualVersion > myVersion) // Porovna verze
                {
                    ApplicationUpdateEventArgs eventArgs = new ApplicationUpdateEventArgs();
                    eventArgs.ActualVersion = actualVersion;
                    eventArgs.userState = state;
                    eventArgs.eventType = ApplicationUpdateEventType.NEWVERSIONAVAILABLE;
                    Tools.RiseSynchronizedEvent<ApplicationUpdateEventArgs>(this, OnVersionGet, eventArgs);
                } else
                {
                    ApplicationUpdateEventArgs eventArgs = null;

                    // Overi betaverze
                    if (SettingsManager.Instance.Data.BetaInform && !Tools.AssemblyVersion.Contains("beta"))
                    {
                        if (textData.IndexOf("Je k dispozici betaverze!") != -1)
                        {
                            eventArgs = new ApplicationUpdateEventArgs();
                            eventArgs.userState = state;
                            eventArgs.eventType = ApplicationUpdateEventType.NEWBETAVERSIONAVAILABLE;
                            Tools.RiseSynchronizedEvent<ApplicationUpdateEventArgs>(this, OnVersionGet, eventArgs);
                        }
                    }

                    eventArgs = new ApplicationUpdateEventArgs();
                    eventArgs.ActualVersion = actualVersion;
                    eventArgs.userState = state;
                    eventArgs.eventType = ApplicationUpdateEventType.NEWVERSIONNOTAVAILABLE;
                    Tools.RiseSynchronizedEvent<ApplicationUpdateEventArgs>(this, OnVersionGet, eventArgs);
                }
            } catch { }        
        }

        /// <summary>
        /// Stahne asynchronne soubor z internetu
        /// </summary>
        /// <param name="version"></param>
        /// <param name="form"></param>
        public void downloadNewVersionAsync(Form parentForm, Version version, DownloadProgress form)
        {
            if (version == null || form == null) return;

            progressForm = form;
            progressForm.FormClosed += parentFormClosing;

            String tempDir = Environment.GetEnvironmentVariable("TEMP");
            if (String.IsNullOrEmpty(tempDir))
            {
                tempDir = Environment.GetEnvironmentVariable("TMP");
            }

            if (String.IsNullOrEmpty(tempDir))
            {
                tempDir = Environment.SpecialFolder.ApplicationData.ToString();
            }

            tempFile = tempDir + "\\Setup" + version + ".exe";
            
            webClient.DownloadProgressChanged += form.downloadProgressChanged;
            webClient.DownloadFileAsync(new Uri(fileSite + "Setup" + version + ".exe"), tempFile);

            form.ShowDialog(parentForm);
        }

        private void parentFormClosing(object sender, EventArgs e)
        {
            webClient.CancelAsync();
        }

        private void downloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            if (!e.Cancelled && e.Error == null && !String.IsNullOrEmpty(tempFile))
            {
                progressForm.Close();
                Thread.Sleep(100);
                ApplicationUpdateEventArgs eventArgs = new ApplicationUpdateEventArgs();                
                eventArgs.userState = tempFile;
                eventArgs.eventType = ApplicationUpdateEventType.NEWVERSIONDOWNLOADED;
                Tools.RiseSynchronizedEvent<ApplicationUpdateEventArgs>(this, OnVersionGet, eventArgs);                
            }

            tempFile = null;
        }
    }
}